/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.icee.myth.utils;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 *
 * @author chencheng
 */
public class MLogger implements Runnable {

    private static MLogger INSTANCE;
    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private final LinkedTransferQueue<MLogMessage> q;
    private BufferedWriter moneyBw;
    private BufferedWriter itemBw;
    private BufferedWriter petBw;
    private BufferedWriter behaviorBw;
    private BufferedWriter debugBw;
    private BufferedWriter dberrBw;
    private BufferedWriter neterrBw;
    private BufferedWriter gameerrBw;
    private int flush_interval;

    public static void init(String pathname, int flush_interval) {
        if (INSTANCE == null) {
            INSTANCE = new MLogger(pathname, flush_interval);
        }
    }

    public static MLogger getlogger() {
        return INSTANCE;
    }

    private MLogger(String pathname) {
        this(pathname, 5000);
    }

    private MLogger(String pathname, int flush_interval) {
        q = new LinkedTransferQueue<MLogMessage>();

        try {
            createDirectoryIfNotExist(LogConsts.LOGPATHROOT + pathname + "/core");
            createDirectoryIfNotExist(LogConsts.LOGPATHROOT + pathname + "/behavior");
            createDirectoryIfNotExist(LogConsts.LOGPATHROOT + pathname + "/debug");
            createDirectoryIfNotExist(LogConsts.LOGPATHROOT + pathname + "/error");

            moneyBw = new BufferedWriter(new FileWriter(LogConsts.LOGPATHROOT + pathname + "/core/money.log", true), LogConsts.LOG_BUFFER_SIZE);
            itemBw = new BufferedWriter(new FileWriter(LogConsts.LOGPATHROOT + pathname + "/core/item.log", true), LogConsts.LOG_BUFFER_SIZE);
            petBw = new BufferedWriter(new FileWriter(LogConsts.LOGPATHROOT + pathname + "/core/pet.log", true), LogConsts.LOG_BUFFER_SIZE);
            behaviorBw = new BufferedWriter(new FileWriter(LogConsts.LOGPATHROOT + pathname + "/behavior/behavior.log", true), LogConsts.LOG_BUFFER_SIZE);
            debugBw = new BufferedWriter(new FileWriter(LogConsts.LOGPATHROOT + pathname + "/debug/debug.log", true), LogConsts.LOG_BUFFER_SIZE);
            dberrBw = new BufferedWriter(new FileWriter(LogConsts.LOGPATHROOT + pathname + "/error/dberror.log", true), LogConsts.LOG_BUFFER_SIZE);
            neterrBw = new BufferedWriter(new FileWriter(LogConsts.LOGPATHROOT + pathname + "/error/neterror.log", true), LogConsts.LOG_BUFFER_SIZE);
            gameerrBw = new BufferedWriter(new FileWriter(LogConsts.LOGPATHROOT + pathname + "/error/gameerr.log", true), LogConsts.LOG_BUFFER_SIZE);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        this.flush_interval = flush_interval;
        new Thread(this).start();
    }

    private String now() {
        return sdf.format(new Date());
    }

    private void createDirectoryIfNotExist(String path) {
        File dir = new File(path);
        if (!dir.exists()) {
            dir.mkdirs();
        }
    }

    public void debuglog(int severity, String msg) {
        if (LogConsts.LOG_CONSOLE_PRINT == 1) {
            System.err.println(now() + "\t" + msg);
        }

        if (severity <= LogConsts.LOGLEVEL) {
            q.offer(new MLogMessage(LogConsts.LOGTYPE_DEBUG, severity, msg));
        }
    }

    public void log(int category, String msg) {
        if (LogConsts.LOG_CONSOLE_PRINT == 1) {
            System.err.println(now() + "\t" + msg);
        }

        q.offer(new MLogMessage(category, LogConsts.LOGLEVEL_DEBUG, msg));
    }

    public void run() {
        long start = System.currentTimeMillis();
        long end;
        try {
            while (true) {
                MLogMessage lmsg = q.poll();
                while (lmsg != null) {

                    switch (lmsg.category) {
                        case (LogConsts.LOGTYPE_DEBUG): {
                            switch (lmsg.severity) {
                                case LogConsts.LOGLEVEL_ERROR: {
                                    debugBw.write(now() + "\t[ERROR]: " + lmsg.msg);
                                    debugBw.newLine();
                                    break;
                                }
                                case LogConsts.LOGLEVEL_INFO: {
                                    debugBw.write(now() + "\t[INFO]: " + lmsg.msg);
                                    debugBw.newLine();
                                    break;
                                }
                                case LogConsts.LOGLEVEL_DEBUG: {
                                    debugBw.write(now() + "\t[DEBUG]: " + lmsg.msg);
                                    debugBw.newLine();
                                    break;
                                }
                            }
                            break;
                        }
                        case (LogConsts.LOGTYPE_BEHAVIOR): {
                            behaviorBw.write(now() + "\t" + lmsg.msg);
                            behaviorBw.newLine();
                            break;
                        }
                        case (LogConsts.LOGTYPE_MONEY): {
                            moneyBw.write(now() + "\t" + lmsg.msg);
                            moneyBw.newLine();
                            break;
                        }
                        case (LogConsts.LOGTYPE_ITEM): {
                            itemBw.write(now() + "\t" + lmsg.msg);
                            itemBw.newLine();
                            break;
                        }
                        case (LogConsts.LOGTYPE_PET): {
                            petBw.write(now() + "\t" + lmsg.msg);
                            petBw.newLine();
                            break;
                        }
                        case (LogConsts.LOGTYPE_DBERR): {
                            dberrBw.write(now() + "\t" + lmsg.msg);
                            dberrBw.newLine();
                            break;
                        }
                        case (LogConsts.LOGTYPE_NETERR): {
                            neterrBw.write(now() + "\t" + lmsg.msg);
                            neterrBw.newLine();
                            break;
                        }
                        case (LogConsts.LOGTYPE_GAMEERR): {
                            gameerrBw.write(now() + "\t" + lmsg.msg);
                            gameerrBw.newLine();
                            break;
                        }
                    }
                    lmsg = q.poll();
                }

                Thread.sleep(100);

                // auto-flush every flush_interval milliseconds
                end = System.currentTimeMillis();
                if (end - start >= flush_interval) {
                    moneyBw.flush();
                    itemBw.flush();
                    petBw.flush();
                    behaviorBw.flush();
                    debugBw.flush();
                    dberrBw.flush();
                    neterrBw.flush();
                    gameerrBw.flush();
                    start = end;
                }
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (InterruptedException ie) {
            ie.printStackTrace();
        }
    }

    private class MLogMessage {

        public int category;
        public int severity;
        public String msg;

        public MLogMessage(int category, int severity, String msg) {
            this.category = category;
            this.severity = severity;
            this.msg = msg;
        }
    }
}
